查看原文
其他

深入理解Java虚拟机(一): 内存区域

老王和小杨 Java学习之道 2021-12-16

点击上方"淼淼之森",选择"关注"公众号

优秀文章,第一时间收到!

KS

Knowledge Sharing

知识分享

    现在是资源共享的时代,同样也是知识分享的时代,如果你觉得本文有用,希望你能将它分享,让更多的人看到。

推荐阅读

1、神站推荐

2、资源汇总整理分享

3、好用的Chrome插件推荐

4、设计模式精炼: 汇总篇

Java内存区域

运行时数据区域

Java在运行时会把它所管理的内存划分为若干个不同的数据区域。

方法区(Method Area)

      (1)线程共享

      (2)存储

    类信息

    常量

    静态变量

    即时编译器编译后的代码

    (3)非堆

    (4)不需要连续的内存

    (5)可以选择固定或可扩展

    (6)可选择不实现垃圾收集

    (7)针对常量池的回收


    • 运行时常量池(Runtime Constant Pool)

            a、常量池:存放编译期生成的字面常量和符号引用

            b、这些常量池中的数据进入方法区后存放在运行时常量池中

            c、动态性:运行期可将新的常量放入池中,例如:String.intern()方法

    (8)对类型的卸载

    (9)无法满足内存分配需求时会抛出OutOfMemoryError

虚拟机栈(VM Stack)

        (1)线程私有

        (2)生命周期与线程相同

        (3)描述Java方法执行的内存模型

        (4)栈帧

            a、局部变量表:基本数据类型、对象引用和returnAddress类型(指向一条字节码指令的地址)

            b、操作数栈

            c、动态链接

            d、方法出口

            e、64位的long 和double会占用两个局部变量空间,其余的只占一个

            f、编译期完成内存分配

            g、方法运行期间不会改变局部变量表的大小

            h、存储

            i、入栈

            j、出栈

    (5)线程请求的栈深度大于虚拟机允许的深度会抛出StackOverFlowError

    (6)如果扩展时无法申请到足够内存会抛出OutOfMemoryError

本地方法栈(Native Method Stack)

    (1)为本地方法(Native Method)服务

    (2)<--> 区别于虚拟机栈:为虚拟机执行Java方法服务。

    (3)抛出StackOverFlowError

    (4)抛出OutOfMemoryError

堆(Heap)

    (1)Java虚拟机所管理的内存中最大的一块
    (2)线程共享
    (3)虚拟机启动时创建
    (4)存放对象实例及数组
    (5)垃圾回收管理(GC)主要区域
         - 分代算法
            | 新生代
                eden
                from
                to
            | 老年代
    (6)可划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)
    (7)可处于物理上不连续的内存空间,保证逻辑连续即可
    (8)可通过-Xmx和-Xms控制大小(可扩展)
    (9)堆无法再扩展时会抛出OutOfMemoryError

程序计数器(Program Counter Register)

    (1)较小内存空间

    (2)当前线程的行号指示器

    (3)线程私有的内存

    (4)唯一一个没有OutOfMemoryError的区域

直接内存(Direct Memory)

    (1)NIO中使用基于通道(Channel)与缓冲区(Buffer)的I/O方式,使用Native函数库直接分配的堆外内存

    (2)无法满足内存分配需求时会抛出OutOfMemoryError

对象的创建

  • (1)类加载检查机制

  • (2)为新生对象分配内存

  • (3)把一块确定大小的内存从堆中划分出来。

    • 选择方式由Java堆是否规整决定

    • Java堆是否规整由垃圾收集器是否带有压缩整理功能决定。

    • 由于对象创建是非常频繁的,则在并发情况下不是线程安全的

    • 对分配内存空间的动作进行同步处理

    • 把内存分配的动作按照线程划分在不同的空间中,即TLAB方式。

    • 只有在TLAB用完并分配新TLAB的情况下需要同步锁定

    • 可以使用-XX:+/-UseTLAB来设定

    • 内存规整: 指针碰撞(Bump the Point)

    • 内存不规整 空闲列表(Free List):维护列表并记录哪些是可用的。

  • (4)将分配到的内存空间初始化为0(不包含对象头)

  • (5)对对象进行必要的设置

  • (6)属于哪个类的实例

  • (7)如何找到类的元数据信息

  • (8)对象的哈希值

  • (9)对象的GC分代年龄

  • (10)这些数据存放在对象头(Object Header)中

  • (11)对象得到创建,但是所有的字段为零,在执行new之后会立即执行方法

对象的内存布局

(1)对象头(Object Header)
    存储对象自身运行时数据(Mark Word),通常在32位和64位的机器上占用32bit和64bit的空间
        哈希吗
        GC分代年龄
        锁状态标志
        线程持有锁
        偏向线程ID
        偏向时间戳
(2)类型指针: 对象指向它的类元数据的指针
    a、虚拟机通过这个指针来确定这个对象属于哪个类

    b、不是所有的对象实例都保留有类型指针
    c、如果对象是数组,还必须有一块用于记录数组长度的数据
(3)实例数据(Instance Data),真正存储的数据
    存储顺序受到虚拟机分配策略参数(Fields Allocation Style)和字段在Java源码中的定义顺序影响
(4)对齐填充(Padding)
    a、不是必要存在的
    b、仅仅起占位作用

对象访问定位

    Java通过栈上的引用(reference)数据来操作堆上的具体对象

句柄访问

(1)堆中划分一块内存作为句柄池

(2)reference中存储对象的句柄地址

(3)句柄中包含对象实例数据与类型数据各自的具体地址信息

优点:reference中存储稳定的句柄地址,在对象移动时只会改变句柄中的实例数据指针

直接指针

(1)考虑如何放置访问类型数据的相关信息

(2)reference中直接存储对象地址

优点:速度更快,节省一次指针定位的时间

-END-

本文参考《深入理解Java虚拟机》(第二版)

关注公众号"淼淼之森"获取更多精彩信息:

据说幸运的人都会第一时间关注哦!

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存